package com.autumn.context.utils;

import com.autumn.context.annotation.Component;
import com.autumn.context.annotation.Order;

import java.lang.annotation.Annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.Method;

/**
 * @author niann
 * @description
 * @date 2023/12/21 22:51
 */
public class ClassUtils {


    /**
     * TODO 递归查找 annotation1
     *
     * @param clazz
     * @param annotationClass
     * @param <E>
     * @return
     */
    public static <E> E findAnnotation(Class<?> clazz, Class<E> annotationClass) {
        if (clazz == null || annotationClass == null) {
            return null;
        }
        Annotation[] annotations = clazz.getAnnotations();
        for (Annotation annotation : annotations) {
            Class<? extends Annotation> annotationType = annotation.annotationType();
            if (annotationType.getName().equals(annotationClass.getName())) {
                return (E) annotation;
            } else if (!isNativeAnno(annotation)) {
                return findAnnotation(annotationType, annotationClass);
            }
        }
        return null;
    }

    private static boolean isNativeAnno(Annotation annotation) {
        return
                annotationEquals(annotation, Documented.class) ||
                        annotationEquals(annotation, Target.class) ||
                        annotationEquals(annotation, Retention.class);
    }


    private static <E> Method findMethodAnnotation(Method method, Class<E> annotationClass) {
        Annotation[] annotations = method.getAnnotations();
        for (Annotation annotation : annotations) {
            Class<? extends Annotation> annotationType = annotation.annotationType();
            if (annotationType.getTypeName().equals(annotationClass.getTypeName())) {
                return method;
            }
        }
        return null;
    }

    public static <E> E findMethodAnnotation(Class<?> clazz, Class<E> annotationClass) {
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            if (findMethodAnnotation(method, annotationClass) != null) {
                Annotation[] annotations = method.getAnnotations();
                for (Annotation annotation : annotations) {
                    String typeName01 = annotation.annotationType().getTypeName();
                    String typeName02 = annotationClass.getTypeName();
                    if (typeName01.equals(typeName02)) {
                        return (E) annotation;
                    }
                }
            }
        }
        return null;
    }

    public static int getOrder(Class<?> clazz) {
        Order order = findAnnotation(clazz, Order.class);
        return order != null ? order.value() : 0;
    }

    public static <E> Method findAnnotationMethod(Class<?> clazz, Class<E> annotationClass) {
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            if (findMethodAnnotation(method, annotationClass) != null) {
                return method;
            }
        }
        return null;
    }


    public static void main(String[] args) {
    }


    public static boolean annotationEquals(Annotation annotation1, Annotation annotation2) {
        return annotation1.annotationType().getTypeName().equals(annotation2.annotationType().getTypeName());
    }

    public static boolean annotationEquals(Annotation annotation1, Class<?> annotationClass) {
        return annotation1.annotationType().getTypeName().equals(annotationClass.getTypeName());
    }

    /**
     * 查找Component，未找到则查找其他注解是否有Component
     * Component注解value值为null默认则当前包
     *
     * @param clazz
     * @return 包名：xxx.xxx
     */
    public static String getBeanName(Class<?> clazz) {
        Component component = findAnnotation(clazz, Component.class);
        if (component != null) {
            return
                    component.value() != null && !component.value().isEmpty() ?
                            component.value() :
                            clazz.getSimpleName();
        } else {
            Annotation[] annotations = clazz.getAnnotations();
            for (Annotation annotation : annotations) {
                Annotation[] subAnnos = annotation.annotationType().getAnnotations();
                for (Annotation subAnno : subAnnos) {
                    if (annotationEquals(subAnno, Component.class)) {
                        String className = ((Component) subAnno).value();
                        return
                                className != null && !className.isEmpty() ?
                                        className :
                                        clazz.getSimpleName();
                    }
                }
            }
        }
        throw new RuntimeException("%s Component注解不存在".formatted(clazz.getTypeName()));
    }


}
